<template>
  <div class="multipleSelect">
    <div style="display: flex; align-items: center">
      <!-- 已选择的列表 -->
      <ul class="selected">
        <el-tooltip v-for="item in selectList" :key="item.value" effect="dark" :content="item.label" placement="top">
          <li class="item">
            {{ item.label.slice(0, 1) }}
            <i v-if="!disabled" class="el-icon-close" @click="delItem(item)"></i>
          </li>
        </el-tooltip>
      </ul>

      <!-- 弹出层选择器 -->
      <el-popover v-model="visible" placement="bottom-start" width="150" trigger="manual" popper-class="message-popover">
        <ul v-if="options.length > 0" class="group">
          <li
            v-for="(item, index) in dataList"
            :key="index"
            class="multiple"
            :style="{
              color: value.includes(item.value) ? 'rgb(29, 167, 106)' : '#000',
              background: value.includes(item.value) ? 'rgb(240, 240, 240)' : '#fff'
            }"
            @click="select(item)"
          >
            <div class="label">{{ item.label }}</div>
            <div v-show="value.includes(item.value)" class="icon">
              <i class="el-icon-check"></i>
            </div>
          </li>
        </ul>
        <div v-else class="empty">无数据</div>

        <template #reference>
          <div
            :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
            class="icon-add"
            @click="disabled ? (visible = false) : (visible = true)"
          ></div>
        </template>
      </el-popover>
    </div>
  </div>
</template>

<script setup name="MultipleSelect" lang="ts">
import { ref, computed, watch, onMounted } from 'vue';

const props = defineProps({
  options: {
    type: Array,
    default: () => []
  },
  value: {
    type: Array,
    default: () => []
  },
  keyName: String,
  valueName: String,
  disabled: {
    type: Boolean,
    default: false
  }
});

const emit = defineEmits(['update:value', 'change']);

const visible = ref(false);
const selectList = ref([]);

// 处理数据列表
const dataList = computed(() => {
  if (props.options.length > 0) {
    return props.options.map((item) => ({
      label: item[props.keyName || 'label'],
      value: item[props.valueName || 'value']
    }));
  }
  return [];
});

// 选中数据
const select = (data) => {
  if (!props.value.includes(data.value)) {
    selectList.value.push(data);
    const check = selectList.value.map((i) => i.value);
    emit('update:value', check);

    if (props.value.length !== check.length) {
      emit('change', { type: 'add', value: data.value, values: check });
    }
    visible.value = false;
  }
};

// 删除数据
const delItem = (data) => {
  selectList.value.splice(props.value.indexOf(data.value), 1);
  const check = selectList.value.map((i) => i.value);
  emit('update:value', check);

  if (props.value.length !== check.length) {
    emit('change', { type: 'del', value: data.value, values: check });
  }
};

// 监听 props.value 变化更新选中列表
watch(
  () => props.value,
  (val) => {
    const list = [];
    val.forEach((i) => {
      dataList.value.forEach((j) => {
        if (i === j.value) {
          list.push(j);
        }
      });
    });
    selectList.value = list;
  },
  { immediate: true }
);

// 监听外部点击关闭弹出层
onMounted(() => {
  document.addEventListener('mouseup', (e) => {
    const dom1 = document.querySelector('.icon-add');
    if (dom1 && !dom1.contains(e.target)) {
      visible.value = false;
    }
  });
});
</script>

<style lang="scss" scoped>
.multipleSelect {
  user-select: none;
  display: flex;
  align-items: center;

  .selected {
    display: flex;
    list-style: none;
    padding: 0;
    margin: 0;

    .item {
      width: 35px;
      height: 35px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-right: 10px;
      cursor: pointer;
      color: rgb(29, 167, 106);
      background: rgb(235, 250, 243);
      position: relative;
      font-weight: bold;

      .el-icon-close {
        position: absolute;
        right: -5px;
        top: -5px;
        visibility: hidden;
        background: rgb(29, 167, 106);
        color: #fff;
        border-radius: 50%;
        padding: 2px;
        transform: scale(0.6, 0.6);
      }

      &:hover .el-icon-close {
        visibility: visible;
      }
    }
  }

  .icon-add {
    cursor: pointer;
    width: 35px;
    height: 35px;
    border: 1px solid #aaa;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;

    &:hover {
      border-color: rgb(29, 167, 106);

      &::before,
      &::after {
        background: rgb(29, 167, 106);
      }
    }

    &::before,
    &::after {
      content: '';
      position: absolute;
      transform: translate(-50%, -50%);
    }

    &::before {
      width: 30%;
      height: 2px;
      background: #aaa;
      left: 50%;
      top: 50%;
    }

    &::after {
      height: 30%;
      width: 2px;
      background: #aaa;
      left: 50%;
      top: 50%;
    }
  }
}

.group ::v-deep {
  list-style: none;
  padding: 0;
  margin: 0;
  max-height: 200px;
  overflow: auto;

  .multiple {
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    height: 35px;
    line-height: 35px;

    &:hover {
      background: rgb(240, 240, 240) !important;
    }

    .label {
      width: 70%;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      padding-left: 10px;
    }

    .icon {
      width: 20%;
    }
  }
}

.empty {
  text-align: center;
}
</style>
